-- CombatStatM
-- create by weism
-- 战斗统计信息模块

module("CombatStatM", package.seeall);

-- 统计信息
local statInfo = {};

-- 配置信息
local config = {};
local ruleMap  = {};

-- 所有子规则
local rules = {};

-- 奖励信息
local bonusInfo = nil;

local fieldStat = {};

-- 回合击杀统计
local roundKills = {};

local whenCombatRound;
local whenMonsterDie;

local whenDoBonus;

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    -- 转换下combat_stat信息表
    local combat_stat_CSV = get_combat_stat_CSV();
    for i = 1, #combat_stat_CSV do
        local id = combat_stat_CSV[i].id;

        config[id] = combat_stat_CSV[i];

        ruleMap[combat_stat_CSV[i].rule] = id;
    end
    combat_stat_CSV = {};

    fieldStat  = {};
    roundKills = {};

    -- 转换下dungeon_appear_stat信息表
    local dungeon_appear_stat_CSV = get_dungeon_appear_stat_CSV();
    for i = 1, #dungeon_appear_stat_CSV do
        local row = dungeon_appear_stat_CSV[i];
        local field = row.field;

        fieldStat[field] = row;
    end
    dungeon_appear_stat_CSV = {};
end

-- 初始
function init()
    if not _init then
        loadCsv();

        -- 载入所有的规则处理子模块
        rules = LOAD_PATH("game/logic/module/combat_stat");
    end

    EventMgr.removeAll("CombatStatM");

    -- 监听离开迷宫模块
    EventMgr.register("CombatStatM", event.LEAVE_DUNGEON, function(para)
        ME.user.dbase:delete("dungeon_field_stat");
    end);
    -- 关注奖励事件
    EventMgr.register("CombatStatM", event.DO_BONUS, whenDoBonus);

    -- 回合结束
    CombatM.registerEndRoundCB("round_end_stat_kill", whenCombatRound);

    -- 怪物死亡事件
    EventMgr.register("CombatStatM", event.MONSTER_DIE_LOGIC, whenMonsterDie);
end

whenCombatRound = function(para)
    -- 如果没有击杀数据
    if sizeof(roundKills) <= 0 then
        return;
    end

    EventMgr.fire(event.ROUND_KILL_STAT, roundKills);

    -- 情况这回合击杀就行
    roundKills = {};
end

whenMonsterDie = function(para)
    local monster = para.monster;
    if not monster then
        return;
    end

    local base_id = monster:query("base_class_id") or monster.classId;
    roundKills[base_id] = (roundKills[base_id] or 0) + 1;
end

-- 奖励回调
whenDoBonus = function(para)
    -- 如果不是在迷宫内的
    if not DungeonM.isInDungeon() then
        return;
    end

    addFieldStat(para[2], para[3]);
end

-- 检索统计项信息
function query(id, path)
    local m = config[id] or {};

    if not path then
        return m;
    end

    return m[path];
end

-- 获取回合击杀数据
function queryRoundKill(classId)
    if not classId then
        return roundKills;
    end

    return roundKills[classId] or 0;
end

-- 根据类型索引
function queryByRule(rule, path)
    local id = ruleMap[rule];

    if id then
        return query(id, path);
    end
end

-- 清空统计信息
function clear()
    statInfo = {};
    bonusInfo = nil;
end

-- 更新战斗统计数据
function updateStat(stat)
    statInfo = stat;
end

-- 返回统计信息
function getStatInfo()
    local ret = {};
    for id, value in pairs(statInfo) do
        -- 统计一下
        ret[query(id, "rule")] = value;
    end
    return ret;
end

-- 查询进度
function getProgress(id)
    return statInfo[id] or 0;
end

-- 设置进度
function setProgress(id, progress)
    statInfo[id] = progress;
end

-- 增加进度
function addProgress(id, add)
    add = add or 1;

    local curr = statInfo[id] or 0;
    statInfo[id] = curr + add;
    --print("addProgress: id-"..id..", tatal:"..statInfo[id]);
end

-- 计算战斗统计信息及奖励
function calcCombatStat()

    -- 先去掉状态影响
    CombatStatusM.clearAllStatus(ME.user);

    local ret = { ["detail"] = {}, };

    local sum = 0;
    -- 迷宫评分
    ret.score1 = 0;
    for i = 1, 12 do
        local rule = rules[query(i, "rule")];
        local progress = rule.progress();

        if query(i, "join") == 1 then
            -- 累计积分
            local score = FormulaM.invoke("CALC_COMBAT_STAT", ME.user, i, progress);
            print("id:"..i..", progress:"..progress..", score:"..score);
            sum = sum + score;
            ret.score1 = ret.score1 + score;
        end
    end

    -- 属性评分
    ret.score2 = 0;
    for i = 7, 10 do
        local rule = rules[query(i, "rule")];
        local progress = rule.progress();

        -- 累计积分
        local score = FormulaM.invoke("CALC_COMBAT_STAT", ME.user, i, progress);
        print("id:"..i..", progress:"..progress..", score:"..score);
        sum = sum + score;
        ret.score2 = ret.score2 + score;
    end

    print("累计评分:"..sum);

    -- 技能评分
    ret.score3 = 0;
    local skillList = ME.user:getAllSkills(true);
    for i = 1, #skillList do
        local level = SkillM.query(skillList[i], "level");
        local score = FormulaM.invoke("CALC_COMBAT_SKILL_STAT", ME.user, level);
        sum = sum + score;
        ret.score3 = ret.score3 + score;
    end

    print("技能评分:"..sum);
    printTable(skillList, "技能列表");

    -- 宝物评分
    ret.score4 = 0;
    local treasure = EquipM.getUserTreasureList();
    for classId, amount in pairs(treasure) do
        local rank = EquipM.getRealRank(classId);
        local score = FormulaM.invoke("CALC_COMBAT_TREASURE_STAT", ME.user, rank) * amount;
        sum = sum + score;
        ret.score4 = ret.score4 + score;
    end

    -- 神器
    local artifactId = ME.user:getCarryArtifact();
    if artifactId ~= 0 then
        local amount = ItemM.getAmount(ME.user, artifactId);
        if amount > 0 then
            local rank = ItemM.query(artifactId, "rank");
            local score = FormulaM.invoke("CALC_COMBAT_TREASURE_STAT", ME.user, rank);
            sum = sum + score;
            ret.score4 = ret.score4 + score;
            print("神器评分:"..score);
        end
    end

    print("宝物评分:"..sum);

    -- 总积分
    ret.sum = sum;

    -- 奖励
    ret.bonus = FormulaM.invoke("CALC_COMBAT_END_BONUS", ME.user, sum)

    return ret;
end

-- 获取战斗统计信息
function getCombatStat()
    if bonusInfo == nil then
        bonusInfo = calcCombatStat();
    end

    return bonusInfo;
end

-- 战斗结算奖励
function combatEndBonus(dungeonId, layer)
    -- 奖励前先收集一下玩家当前的经验和等级
    -- 用于结算界面表现
    ME.user.oriExpInfo = {
        ["exp"] = ME.user:getExp(),
        ["level"] = ME.user:getLevel(),
    };

    local info = getCombatStat();

    -- 计算奖励
    local bonus = info.bonus;
    for _, arr in pairs(bonus) do
        BonusM.doBonus(arr, "combat_end");
    end

    -- 记录最高分
    local dungeonScore = ME.user.dbase:query("dungeon_score", {});

    local score = dungeonScore[dungeonId] or 0;
    dungeonScore[dungeonId] = math.max(score, info.sum);

    ME.user.dbase:set("dungeon_score", dungeonScore);

    -- 记录最近一次的得分
    ME.user.dbase:setTemp("last_dungeon_score", {
        ["dungeon_id"] = dungeonId,
        ["score"] = info.sum,
        ["layer"] = layer,
    });

    if info.sum > score then
        -- 抛出迷宫得分刷新的事件
        EventMgr.fire(event.DUNGEON_SCORE_REFRESH, { ["dungeonId"] = dungeonId, ["score"] = info.sum, });
    end

    -- 抛出事件
    EventMgr.fire(event.DUNGEON_COMBAT_END, info);

    -- 奖励之后就删除数据，前面的事件需要用到，翻到后面清除
    clear();

    return info;
end

-- 增加统计
function addFieldStat(field, add)
    if not fieldStat[field] then
        return 0;
    end

    add = add or 1;

    local id = fieldStat[field]["id"];
    if not id then
        return 0;
    end

    local stat = ME.user.dbase:query("dungeon_field_stat", {});
    local count = (stat[id] or 0) + add;
    stat[id] = count;

    ME.user.dbase:set("dungeon_field_stat", stat);

    return count;
end

-- 获取统计
function getFieldStat(field)
    -- 如果没有配置
    if not fieldStat[field] then
        return 0;
    end

    local id = fieldStat[field]["id"];
    if not id then
        return 0;
    end

    local stat = ME.user.dbase:query("dungeon_field_stat", {});

    return stat[id] or 0;
end

-- 解压迷宫属性统计
function unpackDungeonFieldStat(buff)
    if not buff then
        return;
    end

    local buffer = Buffer.create(buff);

    local offset = 1;
    local size = Buffer.size(buffer);
    local stat = ME.user.dbase:query("dungeon_field_stat", {});

    while (offset <= size) do
        local count = Buffer.getu16(buffer, offset);
        if (count > 0) then
            local id = math.modf(offset / 2);
            id = id + 1;

            stat[id] = count;
        end

        -- 继续下一个记录
        offset = offset + 2;
    end

    ME.user.dbase:set("dungeon_field_stat", stat);
end

-- 打包战斗统计
function packCombatStat()
    return statInfo;
end
